package stores

import "jvmgo/ch10/instructions/base"
import "jvmgo/ch10/rtda"
import "jvmgo/ch10/rtda/heap"

// 从操作数栈读取一个引用存入数组
type AASTORE struct {
    base.NoOperandsInstruction
}

func (self *AASTORE) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    ref := stack.PopRef()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    refs := arrRef.Refs()
    checkIndex(len(refs), index)
    refs[index] = ref
}

// 从操作数栈读取一个byte或boolean存入数组
type BASTORE struct {
    base.NoOperandsInstruction
}

func (self *BASTORE) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    val := stack.PopInt()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    bytes := arrRef.Bytes()
    checkIndex(len(bytes), index)
    bytes[index] = int8(val)
}

// 从操作数栈读取一个char存入数组
type CASTORE struct {
    base.NoOperandsInstruction
}

func (self *CASTORE) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    val := stack.PopInt()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    chars := arrRef.Chars()
    checkIndex(len(chars), index)
    chars[index] = uint16(val)
}

// 从操作数栈读取一个double存入数组
type DASTORE struct {
    base.NoOperandsInstruction
}

func (self *DASTORE) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    val := stack.PopDouble()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    doubles := arrRef.Doubles()
    checkIndex(len(doubles), index)
    doubles[index] = float64(val)
}

// 从操作数栈读取一个float存入数组
type FASTORE struct {
    base.NoOperandsInstruction
}

func (self *FASTORE) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    val := stack.PopFloat()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    floats := arrRef.Floats()
    checkIndex(len(floats), index)
    floats[index] = float32(val)
}

// 从操作数栈读取一个int存入数组
type IASTORE struct {
    base.NoOperandsInstruction
}

func (self *IASTORE) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    val := stack.PopInt()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    ints := arrRef.Ints()
    checkIndex(len(ints), index)
    ints[index] = int32(val)
}

// 从操作数栈读取一个long存入数组
type LASTORE struct {
    base.NoOperandsInstruction
}

func (self *LASTORE) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    val := stack.PopLong()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    longs := arrRef.Longs()
    checkIndex(len(longs), index)
    longs[index] = int64(val)
}

// 从操作数栈读取一个short存入数组
type SASTORE struct {
    base.NoOperandsInstruction
}

func (self *SASTORE) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    val := stack.PopInt()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    shorts := arrRef.Shorts()
    checkIndex(len(shorts), index)
    shorts[index] = int16(val)
}

func checkNotNil(ref *heap.Object) {
    if ref == nil {
        panic("java.lang.NullPointerException")
    }
}
func checkIndex(arrLen int, index int32) {
    if index < 0 || index >= int32(arrLen) {
        panic("ArrayIndexOutOfBoundsException")
    }
}